﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using SystemDiagramNew.TypeDefinition;
using SystemDiagramNew.Utils;

namespace SystemDiagramNew
{
	internal class SystemDiagram : IDisposable
	{
		internal SystemDiagram(ExternalCommandData cmdData)
		{
			this.CommandData = cmdData;
		}

		public void Dispose()
		{
		}

		internal virtual bool Run()
		{
			this.Option = SystemDiagramOption.Instance;
			return this.ShowUI() && this.GetElements() && this.CreateView() && this.DrawDiagram();
		}

		internal virtual bool ShowUI()
		{
			SystemDiagramForm systemDiagramForm = new SystemDiagramForm(this.CommandData, this.Option);
			if (systemDiagramForm.ShowDialog() != DialogResult.OK)
			{
				return false;
			}
			this.CurrentSystem = systemDiagramForm.SelectedSystem;
			return true;
		}

		public void Finish()
		{
			if (this._waitingWindow != null)
			{
				this._waitingWindow.Close();
				this._waitingWindow.Dispose();
				this._waitingWindow = null;
			}
		}

		internal ExternalCommandData CommandData { get; set; }

		internal UIDocument UIDocument
		{
			get
			{
				return this.CommandData.Application.ActiveUIDocument;
			}
		}

		internal Document Document
		{
			get
			{
				return this.UIDocument.Document;
			}
		}

		internal SystemDiagramOption Option { get; set; }

		internal Level CurrentLevel { get; set; }

		internal Autodesk.Revit.DB.View CurrentView { get; set; }

		private MEPSystem CurrentSystem { get; set; }

		private SelectedElement SelElement { get; set; }

		internal PipingSystemInfo SystemInfo { get; set; }

		internal IEnumerable<Level> Levels { get; private set; }

		private IEnumerable<Element> SelectedElements { get; set; }

		private IEnumerable<LinkedDocument> LinkedDocuments { get; set; }

		private Autodesk.Revit.DB.View DrawView { get; set; }

		public string ErrorMessage { get; set; }

		internal virtual bool GetElements()
		{
			this.LinkedDocuments = this.CommandData.GetDocument().GetLinkedDocuments();
			this.SelectedElements = Enumerable.Empty<Element>();
			if (!this.GetSystem())
			{
				return false;
			}
			ElementId linePatternId = null;
			int lineWeight = -1;
            Autodesk.Revit.DB.Color lineColor = null;
			PipeInfo.BLineReplace = LineTypeOperate.GetPipeLinePatternAndLineWeight(this.CommandData.Application.ActiveUIDocument.Document, this.CurrentSystem, ref linePatternId, ref lineWeight, ref lineColor);
			if (PipeInfo.BLineReplace)
			{
				PipeInfo.LinePatternId = linePatternId;
				PipeInfo.LineWeight = lineWeight;
				PipeInfo.LineColor = lineColor;
			}
			PipeInfo.CurDoc = this.CommandData.GetDocument();
			this.CurrentView = this.CommandData.View;
			switch (this.Option.SelectionRange)
			{
			case SelectionRange.All:
				this.SelectedElements = this.GetAllDocsElements();
				break;
			case SelectionRange.Floor:
				this.SelectedElements = this.GetFloorElements();
				break;
			case SelectionRange.Box:
				this.SelectedElements = this.GetBoxSelectedElements();
				break;
			}
			return this.SelectedElements != null && this.SelectedElements.Any<Element>();
		}

		private bool GetSystem()
		{
			if (this.Option.SelectionMothod == SelectionMothod.BySystem)
			{
				this.CurrentLevel = this.CommandData.GetCurrentLevel();
				return true;
			}
			SelectedElement firstElement = this.GetFirstElement();
			if (firstElement == null)
			{
				return false;
			}
			MEPCurve mepcurve = firstElement.Element as MEPCurve;
			if (mepcurve == null)
			{
				this.ErrorMessage = "请选择管道实体";
				return false;
			}
			this.SelElement = firstElement;
			this.CurrentSystem = mepcurve.MEPSystem;
			this.CurrentLevel = mepcurve.GetLevel();
			return true;
		}

		private SelectedElement GetFirstElement()
		{
			return this.CommandData.Application.ActiveUIDocument.PickMEPCurve("选择一根管道");
		}

		internal virtual IEnumerable<Element> GetAllElements()
		{
			return this.CurrentSystem.GetAllElements();
		}

		internal virtual List<Element> GetAllDocsElements()
		{
			SearchSystem searchSystem = new SearchSystem(this.CommandData.Application.ActiveUIDocument, SearchSystemFilter.None);
			if (!searchSystem.RunAll(this.SelElement))
			{
				MessageBox.Show("退出程序\n手动退出或搜索失败,可能分支没有连上或者成环，请检查分支连接情况！");
				return null;
			}
			List<Element> list = new List<Element>();
			foreach (SearchNode searchNode in searchSystem.Nodes)
			{
				list.Add(searchNode.Element);
			}
			return list;
		}

		internal virtual IEnumerable<Element> GetFloorElements()
		{
			List<Element> allDocsElements = this.GetAllDocsElements();
			if (this.CurrentLevel != null)
			{
				return from elem in allDocsElements
				where this.IsOnLevel(elem, this.CurrentLevel)
				select elem;
			}
			return allDocsElements;
		}

		private bool IsOnLevel(Element element, Level level)
		{
			if (level == null || element == null)
			{
				return false;
			}
			Level level2 = element.GetLevel();
			if (level2 == null)
			{
				Parameter parameter = element.GetParameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM);
				if (parameter == null)
				{
					return false;
				}
				double num = parameter.AsDouble();
				YJKViewRange floorHeigh = YJKRevitTools.GetFloorHeigh(PipeInfo.CurDoc, this.CurrentView);
				if (floorHeigh.floorM == YJKViewRange.FloorMark.TopFloor)
				{
					if (num >= level.Elevation)
					{
						return true;
					}
				}
				else if (floorHeigh.floorM == YJKViewRange.FloorMark.ButtonFloor)
				{
					if (num <= level.Elevation)
					{
						return true;
					}
				}
				else
				{
					if (floorHeigh.floorM != YJKViewRange.FloorMark.MidFloor)
					{
						return true;
					}
					if (num >= level.Elevation && num <= level.Elevation + floorHeigh.height)
					{
						return true;
					}
				}
			}
			return level2 != null && (level2.Id == level.Id || Math.Abs(level2.Elevation - level.Elevation) < 0.0001);
		}

		internal virtual IEnumerable<Element> GetBoxSelectedElements()
		{
			if (this.CurrentSystem == null)
			{
				return Enumerable.Empty<Element>();
			}
			Selection selection = this.CommandData.Application.ActiveUIDocument.Selection;
			SystemFilter systemFilter = new SystemFilter(this.CurrentSystem);
			IList<Reference> list = selection.PickObjects((Autodesk.Revit.UI.Selection.ObjectType)1, systemFilter, "请选择实体:");
			if (list == null || !list.Any<Reference>())
			{
				return Enumerable.Empty<Element>();
			}
			return from reference in list
			select this.Document.GetElementByRef(reference);
		}

		private string BuildViewName()
		{
			if (this.CurrentSystem != null)
			{
				return string.Format("{0}  {1}", this.CurrentSystem.GetShowName(), "系统轴测图");
			}
			return "";
		}

		internal bool CreateView()
		{
			if (this.CurrentSystem == null)
			{
				this.ErrorMessage = "没有选中任何系统!";
				return false;
			}
			this.SetProceeding("", 1);
			string text = this.BuildViewName();
			this.DrawView = this.CommandData.GetDocument().CreateNewViewDrafting(ref text, this.Option.Scale);
			if (this.DrawView == null)
			{
				this.ErrorMessage = "创建视图失败!";
				return false;
			}
			this.SetProceeding("", 1);
			this.CommandData.Application.ActiveUIDocument.SetActiveView(this.DrawView);
			return true;
		}

		public void SetProceeding(string message = "", int step = 1)
		{
			if (this._waitingWindow == null)
			{
				return;
			}
			this._progress += step;
			this._waitingWindow.Report(this._progress, message);
		}

		private bool DrawDiagram()
		{
			IntPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
			this._waitingWindow = new LoadingForm();
			this._waitingWindow.Show(mainWindowHandle);
			this.LockRevit();
			this.DrawDiagram2(this._waitingWindow);
			this.UnlockRevit();
			this._waitingWindow.Close();
			return true;
		}

		public void LockRevit()
		{
			this.AllPanels = this.CommandData.Application.GetRibbonPanels();
			this.AllPanels.ToList<RibbonPanel>().ForEach(new Action<RibbonPanel>(this.Lock));
		}

		public void Lock(RibbonPanel panel)
		{
			panel.GetItems().ForEach((RibbonItem item) => item.Enabled = false);
		}

		public void UnlockRevit()
		{
			if (this.AllPanels != null)
			{
				this.AllPanels.ToList<RibbonPanel>().ForEach(new Action<RibbonPanel>(this.Unlock));
			}
		}

		public void Unlock(RibbonPanel panel)
		{
			panel.GetItems().ForEach((RibbonItem item) => item.Enabled = true);
		}

		public bool DrawDiagram2(IProceeding watingWindow)
		{
			string sysName = this.BuildViewName();
			Result result = Result.Failed;
			watingWindow.Report(1, "分析管道系统信息数据...");
			SystemDiagramAnalyser systemDiagramAnalyser = new SystemDiagramAnalyser(this.CommandData)
			{
				Proceeding = watingWindow
			};
			Node.Revit = this.CommandData;
			systemDiagramAnalyser.LinkedDocuments = this.LinkedDocuments.ToList<LinkedDocument>();
			this.SystemInfo = systemDiagramAnalyser.Analyse(sysName, this.SelectedElements, this.Option.Angle, this.Option.ScaleX, this.Option.ScaleY, this.Option.ScaleZ);
			watingWindow.Report(2, "绘制管道系统轴测图...");
			using (Transaction transaction = new Transaction(this.CommandData.Application.ActiveUIDocument.Document, "DrawDiagram"))
			{
				transaction.Start();
				result = new DrawingKit(this.CommandData, this.Option.Angle, this.Option.ScaleLegend)
				{
					View = this.DrawView,
					Proceeding = this._waitingWindow
				}.Drawing(this.SystemInfo, this.Option.LabelPipeDiameter, this.Option.LabelElevation);
				this.CommandData.UpdateModel(false);
				watingWindow.Report(5, "缩放视图到合适范围...");
				UIView uiview = this.CommandData.Application.ActiveUIDocument.GetOpenUIViews().FirstOrDefault((UIView v) => v.ViewId == this.DrawView.Id);
				if (uiview != null)
				{
					uiview.ZoomToFit();
				}
				transaction.Commit();
			}
			return result == 0;
		}

		private const string SystemNameTail = "系统轴测图";

		private LoadingForm _waitingWindow;

		private int _progress;

		private IEnumerable<RibbonPanel> AllPanels;

		public class RevitHandle : IWin32Window
		{
			public IntPtr Handle { get; set; }
		}
	}
}
